package server.entidadCertificadora;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;


/**
 * 
 * @author Mauricio Pradilla Hosie m.pradilla323@uniandes.edu.co
 * @author Martin Uribe Gutierrez m.uribe248@uniandes.edu.co
 * Infraestructura Computacional
 * Universidad de los Andes
 * Algoritmos tomados de: http://www.java2s.com/Code/Java/Security/CatalogSecurity.htm
 * http://www.bouncycastle.org
 * 
 * Clase que modela una entidad certificadora, encargada de brindar las llaves asim�tricas a cada usuario. Act�a como un tercero durante
 * la transacci�n
 */
public class EntidadCertificadora<E>  extends Thread {
	
	
	/**
	 * Puerto Seguro por el cual se va a comunicarse con el servidor
	 */
	public final static int PUERTO = 1025;
	
	public final static int MIN = 10001;
	public final static int MAX = 10002;
	
	private int port;
	
	private KeyPair llaveCliente;
	private KeyPair llaveServidor;
	
	/**
	 * Modela el canal de recepci�n del servidor
	 */
	private ServerSocket serverSocket;
	
	/**
	 * Constructor de la entidad certificadora, inicializa las llaves asim�tricas del servidor y la empresa recaudadora
	 */
	private EntidadCertificadora(int newPort, E newLlaveCliente, E newLlaveServidor){		
		port = newPort;
		llaveServidor = (KeyPair)newLlaveServidor;
		llaveCliente = (KeyPair)newLlaveCliente;
	}
	
	/**
	 * Implementaci�n del m�todo run() la interfaz Thread. 
	 */
	public void run()
	{
		try {			
			serverSocket = new ServerSocket(port);
			System.out.println("Certificadora Iniciada: "+port);
			
			while( true )
			{
				//Crea un nuevo thread por cada conexion.
				Socket nuevaConecion = serverSocket.accept();
				Protocolo p = new Protocolo( nuevaConecion, llaveCliente, llaveServidor.getPublic( ));
				p.start();
				System.out.println("Conexi�n recibida");
			}			
		} 
		catch (IOException e)
		{	
			e.printStackTrace();
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}

	}		
	
	/**
	 * Generador de las llaves asim�tricas
	 * @return las llaves asim�tricas
	 * @throws Exception
	 */
	public static KeyPair generateRSAKeyPair() throws Exception 
	{
		KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
		kpGen.initialize(1024, new SecureRandom());
		return kpGen.generateKeyPair();
	}
	
	/**
	 * Metodo de inicio del servidor.
	 * @param args
	 */
	public static void main(String[] args) 
	{
		try {			
			
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			KeyPair llaveServidor = generateRSAKeyPair( );
			KeyPair llaveCliente = generateRSAKeyPair( );
			Object[] llaves = new Object[2];
			llaves[0] = llaveServidor;
			llaves[1] = llaveCliente.getPublic( );
			File nuevo = new File("data/keys.obj");
			if (nuevo.exists( ))
			{
				nuevo.delete( );
			}
			FileOutputStream fout = new FileOutputStream(nuevo);
			ObjectOutputStream oos = new ObjectOutputStream(fout);
			oos.writeObject(llaves);
			oos.close( );
			System.out.println("Llaves impresas");
			
			for (int i = MIN; i < MAX; i++) {
				EntidadCertificadora<KeyPair> app = new EntidadCertificadora<KeyPair>(i, llaveCliente, llaveServidor);
				app.start();
			}			
			
		} 
		catch (IOException e)
		{	
			e.printStackTrace();
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}	
	}
	
	public static void initialize() 
	{
		try {			
			
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			KeyPair llaveServidor = generateRSAKeyPair( );
			KeyPair llaveCliente = generateRSAKeyPair( );
			Object[] llaves = new Object[2];
			llaves[0] = llaveServidor;
			llaves[1] = llaveCliente.getPublic( );
			File nuevo = new File("data/keys.obj");
			if (nuevo.exists( ))
			{
				nuevo.delete( );
			}
			FileOutputStream fout = new FileOutputStream(nuevo);
			ObjectOutputStream oos = new ObjectOutputStream(fout);
			oos.writeObject(llaves);
			oos.close( );
			System.out.println("Llaves impresas");
			
			for (int i = MIN; i < MAX; i++) {
				EntidadCertificadora<KeyPair> app = new EntidadCertificadora<KeyPair>(i, llaveCliente, llaveServidor);
				app.start();
			}			
			
		} 
		catch (IOException e)
		{	
			e.printStackTrace();
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}		

	}	

}
